package multithreading;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName: Foo
 * @Description 我们提供了一个类：
 *
 * public class Foo {
 * public void first() { print("first"); }
 * public void second() { print("second"); }
 * public void third() { print("third"); }
 * }
 * 三个不同的线程 A、B、C 将会共用一个Foo实例。
 *
 * 一个将会调用 first() 方法
 * 一个将会调用second() 方法
 * 还有一个将会调用 third() 方法
 * 请设计修改程序，以确保 second() 方法在 first() 方法之后被执行，third() 方法在 second() 方法之后被执行。
 *
 * @Author skywingking
 * @Date 2021/11/11 9:43 下午
 **/
public class Foo {
    private AtomicInteger firstJobDone,secondJobDone;
    private Lock lock;
    private Condition firstJobDoneCondition,secondJobDoneCondition;
    public Foo() {
        firstJobDone = new AtomicInteger(0);
        secondJobDone = new AtomicInteger(0);
        lock = new ReentrantLock();
        firstJobDoneCondition = lock.newCondition();
        secondJobDoneCondition = lock.newCondition();
    }

    public void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first". Do not change or remove this line.
        lock.lock();
        try{
            printFirst.run();
            firstJobDone.incrementAndGet();
            firstJobDoneCondition.signal();
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException {
        lock.lock();
        try{
            while (firstJobDone.get() == 0){
                firstJobDoneCondition.await();
            }
            // printSecond.run() outputs "second". Do not change or remove this line.
            printSecond.run();
            secondJobDone.incrementAndGet();
            secondJobDoneCondition.signal();
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }

    public void third(Runnable printThird) throws InterruptedException {
        lock.lock();
        try{
            while (secondJobDone.get() == 0){
                secondJobDoneCondition.await();
            }
            // printThird.run() outputs "third". Do not change or remove this line.
            printThird.run();
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}